package container;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * Description of a weapon.
 * 
 * @author Ioana
 */
@XmlRootElement
public class Weapon implements Comparable<Weapon> {

	private String weaponName;

	private String weaponCode;

	private int weaponCost;

	private int optimalRange;

	private int longRange;

	private List<WeaponTrait> weaponTraits = new ArrayList<WeaponTrait>();

	private int damageMultiplicator;

	private int accuracy;

	@XmlAttribute(name = "Accuracy", required = true)
	public int getAccuracy() {
		return this.accuracy;
	}

	public void setAccuracy(int acc) {
		this.accuracy = acc;
	}

	/**
	 * Adds the passed {@link WeaponTrait} if this trait is not contained in the
	 * actual weapon trait list.
	 * 
	 * @param trait
	 *            trait to add
	 */
	public void addTrait(WeaponTrait trait) {
		if (!getWeaponsTraits().contains(trait)) {
			getWeaponsTraits().add(trait);
			Collections.sort(getWeaponsTraits());
		}

	}

	/**
	 * Removes the passed {@link WeaponTrait}.
	 * 
	 * @param trait
	 *            trait to remove
	 */
	public void removeTrait(WeaponTrait trait) {
		getWeaponsTraits().remove(trait);
	}

	/**
	 * @return the weaponName
	 */
	@XmlAttribute(name = "Name", required = true)
	public String getWeaponName() {
		return this.weaponName;
	}

	/**
	 * @param name
	 *            the weaponName to set
	 */
	public void setWeaponName(String name) {
		this.weaponName = name;
	}

	/**
	 * @return the weaponCode
	 */
	public String getWeaponCode() {
		return this.weaponCode;
	}

	/**
	 * @param code
	 *            the weaponCode to set
	 */
	@XmlAttribute(name = "Code", required = true)
	public void setWeaponCode(String code) {
		this.weaponCode = code;
	}

	/**
	 * @return the weaponCost
	 */
	@XmlAttribute(name = "Cost")
	public int getWeaponCost() {
		return this.weaponCost;
	}

	/**
	 * @param cost
	 *            the weaponCost to set
	 */
	public void setWeaponCost(int cost) {
		this.weaponCost = cost;
	}

	/**
	 * @return the optimalRange
	 */
	@XmlAttribute(name = "Optimal_Range", required = true)
	public int getOptimalRange() {
		return this.optimalRange;
	}

	/**
	 * @param optRange
	 *            the optimalRange to set
	 */
	public void setOptimalRange(int optRange) {
		this.optimalRange = optRange;
	}

	/**
	 * @return the longRange
	 */
	@XmlAttribute(name = "Long_Range", required = true)
	public int getLongRange() {
		return this.longRange;
	}

	/**
	 * @param lngRange
	 *            the longRange to set
	 */
	public void setLongRange(int lngRange) {
		this.longRange = lngRange;
	}

	/**
	 * @return the weaponsTraits
	 */
	@XmlElementWrapper(name = "Weapon_Traits")
	@XmlElement(name = "Weapon_Trait")
	public List<WeaponTrait> getWeaponsTraits() {
		return this.weaponTraits;
	}

	/**
	 * @param traits
	 *            the weaponsTraits to set
	 */
	public void setWeaponsTraits(List<WeaponTrait> traits) {
		this.weaponTraits = traits;
		Collections.sort(this.weaponTraits);
	}

	/**
	 * @return the damageMultiplicator
	 */
	@XmlAttribute(name = "Damage_Multiplicator", required = true)
	public int getDamageMultiplicator() {
		return this.damageMultiplicator;
	}

	/**
	 * @param dmgMultiplicator
	 *            the damageMultiplicator to set
	 */
	public void setDamageMultiplicator(int dmgMultiplicator) {
		this.damageMultiplicator = dmgMultiplicator;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + this.accuracy;
		result = prime * result + this.damageMultiplicator;
		result = prime * result + this.longRange;
		result = prime * result + this.optimalRange;
		result = prime * result
				+ ((this.weaponCode == null) ? 0 : this.weaponCode.hashCode());
		result = prime * result + this.weaponCost;
		result = prime * result
				+ ((this.weaponName == null) ? 0 : this.weaponName.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Weapon other = (Weapon) obj;
		if (this.accuracy != other.accuracy)
			return false;
		if (this.damageMultiplicator != other.damageMultiplicator)
			return false;
		if (this.longRange != other.longRange)
			return false;
		if (this.optimalRange != other.optimalRange)
			return false;
		if (this.weaponCode == null) {
			if (other.weaponCode != null)
				return false;
		} else if (!this.weaponCode.equals(other.weaponCode))
			return false;
		if (this.weaponCost != other.weaponCost)
			return false;
		if (this.weaponName == null) {
			if (other.weaponName != null)
				return false;
		} else if (!this.weaponName.equals(other.weaponName))
			return false;
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int compareTo(Weapon o) {
		return getWeaponCode().compareTo(o.getWeaponCode());
	}

	/**
	 * Returns a string representations of the traits
	 * 
	 * @return a string representation of the traits
	 */
	public String traitsToString() {
		String traits = "";

		for (WeaponTrait trait : getWeaponsTraits()) {
			traits = traits.concat(trait.getTraitCode());
			if (trait.isRatedTrait()) {
				traits = traits.concat("(" + trait.getRating() + ")");
			}
			traits = traits.concat(",");
		}

		if (!traits.isEmpty()) {
			traits = traits.substring(0, traits.length() - 1);
		}

		return traits;
	}
}
